package com.sxhuayuan.parking.plugin.parking.tingzhihui;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sxhuayuan.parking.compenent.Message;
import com.sxhuayuan.parking.compenent.web.RespMessage;
import com.sxhuayuan.parking.config.Platform;
import com.sxhuayuan.parking.dto.CreateMcardChargeOrderDTO;
import com.sxhuayuan.parking.dto.ParkFeeCacheBean;
import com.sxhuayuan.parking.entity.Member;
import com.sxhuayuan.parking.entity.MemberCarPlate;
import com.sxhuayuan.parking.entity.Order;
import com.sxhuayuan.parking.entity.ParkChannel;
import com.sxhuayuan.parking.entity.ParkingIn;
import com.sxhuayuan.parking.entity.ParkingLot;
import com.sxhuayuan.parking.exception.MyException;
import com.sxhuayuan.parking.plugin.parking.ParkingPlugin;
import com.sxhuayuan.parking.plugin.parking.result.McardCancelResultWrap;
import com.sxhuayuan.parking.plugin.parking.result.McardChargeOrderCreateResultWrap;
import com.sxhuayuan.parking.plugin.parking.result.McardQueryChargeOptionsResultWrap;
import com.sxhuayuan.parking.plugin.parking.result.McardQueryResultWrap;
import com.sxhuayuan.parking.plugin.parking.result.ParkingLotInfoQueryResultWrap;
import com.sxhuayuan.parking.plugin.parking.result.QueryParkingFeeResultWrap;
import com.sxhuayuan.parking.plugin.parking.tingzhihui.request.TingzhihuiBaseData;
import com.sxhuayuan.parking.plugin.parking.tingzhihui.request.TingzhihuiOrderSuccessNotifyRequestData;
import com.sxhuayuan.parking.plugin.parking.tingzhihui.request.TingzhihuiQueryExitingCarRequestData;
import com.sxhuayuan.parking.plugin.parking.tingzhihui.request.TingzhihuiQueryFeeRequestData;
import com.sxhuayuan.parking.queue.msg.NotifyParkingLotMsg;
import com.sxhuayuan.parking.service.ExitingCarService;
import com.sxhuayuan.parking.service.OrderService;
import com.sxhuayuan.parking.service.ParkChannelService;
import com.sxhuayuan.parking.service.ParkingInService;
import com.sxhuayuan.parking.service.ParkingLotService;
import com.sxhuayuan.parking.service.impl.pojo.ExitingCar;
import com.sxhuayuan.parking.utils.DateUtils;
import com.sxhuayuan.parking.utils.SettingUtils;
import com.sxhuayuan.parking.utils.SignatureUtils;
import com.sxhuayuan.parking.utils.SpringUtils;

import lombok.extern.log4j.Log4j2;

/**
 * 停智慧停车系统接口
 * 
 * @author gy
 */
@Log4j2
@Component(TingzhihuiParkingPlugin.ID)
public class TingzhihuiParkingPlugin extends ParkingPlugin {

	public static final String ID = "tingzhihuiParkingPlugin";

	public static final String RESP_STATUS = "status";
	public static final int STATUS_SUCCESS = 0;

	@Autowired
	ParkingInService inService;
	@Autowired
	OrderService orderService;
	@Autowired
	ParkingLotService lotService;
	@Autowired
	ExitingCarService exitingCarService;
	@Autowired
	ParkChannelService channelService;

	@Override
	public String getId() {
		return ID;
	}

	@Override
	public String getName() {
		return "停智慧";
	}

	// 支持出入场事件推送
	@Override
	public boolean isSupportEventPush() {
		return true;
	}

	@Override
	public boolean isSupportOrderNotify() {
		return true;
	}

	@Override
	public ParkFeeCacheBean saveParkInRecord(String lotSn, String carPlate, String resp) {
		ParkingLot lot = lotService.findBySn(lotSn);
		// {"fee":3,"entryTime":"2019/7/22 11:23:26","leaveTime":"2019/7/29
		// 11:26:06","feeRate":3,"feeType":null}
		JSONObject jo = JSON.parseObject(resp);
		Date enterTime = DateUtils.parse(jo.getString("entryTime"), "yyyy/MM/dd HH:mm:ss");
		Date endTime = DateUtils.parse(jo.getString("leaveTime"), "yyyy/MM/dd HH:mm:ss");
		Long channelId = null;
		if (jo.containsKey("channel")) {
			ParkChannel channel = channelService.findByDevice(lot.getId(), jo.getString("channel"));
			channelId = channel != null ? channel.getId() : null;
		}
		ParkingIn in = inService.enter(lot, carPlate, enterTime, channelId, lot.getFreeMinutes(), null);
		BigDecimal money = new BigDecimal(jo.getFloat("fee"));
		BigDecimal discount = BigDecimal.ZERO;
		// 更新到出场费用缓存中
		ParkFeeCacheBean bean = new ParkFeeCacheBean();
		bean.setCarPlate(carPlate);
		bean.setDiscountFee(discount.floatValue());
		bean.setEndTime(endTime);
		// bean.setLotOrderNo(String.valueOf(in.getUniqueId()));
		bean.setParkPluginId(ID);
		bean.setTotalFee(SettingUtils.get().setScale(money.add(discount)).floatValue());
		bean.setUniqueId(in.getUniqueId());
		return bean;
	}

	// @Override
	public QueryParkingFeeResultWrap _queryParkingFee(String lotSn, String carPlate) {
		QueryParkingFeeResultWrap rs = new QueryParkingFeeResultWrap();
		rs.setCalcFee(0.01f);
		Date endtime = new Date();
		rs.setCalcStartTime(DateUtils.format(DateUtils.add(endtime, Calendar.MINUTE, -30), DateUtils.YYYYMMDDHHMMSS));
		rs.setCarPlate(carPlate);
		rs.setCalcEndTime(DateUtils.format(endtime, DateUtils.YYYYMMDDHHMMSS));
		rs.setEntertime(rs.getCalcStartTime());
		rs.setExtraPluginId(ID);
		rs.setExtraMchid(lotSn);
		rs.setFee(0.01f);
		rs.setIsSuccess(true);
		rs.setLotOrderNo(RandomStringUtils.randomAlphabetic(10));
		rs.setParktimeMinute(30);
		rs.setTime(new Date());
		return rs;
	}

	@Override
	public QueryParkingFeeResultWrap queryParkingFee(ParkingLot lot, String carPlate) {
		QueryParkingFeeResultWrap rs = new QueryParkingFeeResultWrap();
		if (SettingUtils.get().getIsDebug()) {
			rs.setCalcFee(0.01f);
			Date endtime = new Date();
			rs.setCalcStartTime(DateUtils.format(DateUtils.add(endtime, Calendar.MINUTE, -30), DateUtils.YYYYMMDDHHMMSS));
			rs.setCarPlate(carPlate);
			rs.setCalcEndTime(DateUtils.format(endtime, DateUtils.YYYYMMDDHHMMSS));
			rs.setEntertime(rs.getCalcStartTime());
			rs.setExtraPluginId(ID);
			rs.setExtraMchid(lot.getSn());
			rs.setFee(0.01f);
			rs.setIsSuccess(true);
			rs.setLotOrderNo(RandomStringUtils.randomAlphabetic(10));
			rs.setParktimeMinute(30);
			rs.setTime(new Date());
			return rs;
		}
		TingzhihuiQueryFeeRequestData data = new TingzhihuiQueryFeeRequestData();
		data.setCarPlate(carPlate);
		ParkingIn in = inService.findByCarPlate(lot.getId(), carPlate);
		data.setTime(in.getLastChargeTime());
		String resp = httpPost(lot.getSn(), "/api/fee", data);
		if (resp == null) {
			throw new MyException(RespMessage.Status.ERROR, Message.COMMON_SERVER_CONNECTION_FAILURE);
		}
		JSONObject httpResp = JSON.parseObject(resp);
		boolean isSuccess = httpResp.getIntValue(RESP_STATUS) == STATUS_SUCCESS;
		if (isSuccess) {
			JSONObject respData = httpResp.getJSONObject("data");
			rs.setCardNo(carPlate);
			rs.setCarPlate(carPlate);
			// 总计
			rs.setCalcFee(respData.getFloatValue("fee"));
			// 实收=总计-优惠
			Float fee = respData.getFloatValue("fee");
			rs.setFee(fee);
			rs.setCalcStartTime(respData.getString("entryTime"));
			rs.setCalcEndTime(respData.getString("leaveTime"));
			rs.setExtraMchid(lot.getSn());
			rs.setEntertime(respData.getString("entertime"));
			rs.setParktimeMinute(respData.getInteger("parktime"));
			rs.setExtraPluginId(ID);
			// 车场订单号
			rs.setLotOrderNo("");
			// 车场流水号
			rs.setNo(respData.getString("chargeSeqNo"));
			rs.setRules(respData.getString("priceRule"));
			Long uniqueId = submitUpdateOriginalInfoTask(lot.getSn(), carPlate, fee, resp);
			rs.setUniqueId(uniqueId != null ? String.valueOf(uniqueId) : "");
		} else {
			rs.setMsg(httpResp.getString("message"));
		}
		return rs;
	}

	@Override
	public QueryParkingFeeResultWrap queryLeavingCarParkingLotOrder(ParkingLot lot, String exitSn, Member member) {
		QueryParkingFeeResultWrap rs = null;
		ExitingCar exitingCar = exitingCarService.get(exitSn);
		String carPlate = null;
		if (exitingCar != null) {
			// throw new MyException(Message.API_QUERY_FEE_FAIL);
			carPlate = exitingCar.getCarPlate();
		}
		if (StringUtils.isEmpty(carPlate)) {
			ParkChannel channel = channelService.findBySn(exitSn);
			// 去接口获取
			TingzhihuiQueryExitingCarRequestData data = new TingzhihuiQueryExitingCarRequestData();
			data.setChannel(channel.getDeviceId());
			String resp = httpPost(lot.getSn(), "/api/exits", data);
			if (resp == null) {
				throw new MyException(RespMessage.Status.ERROR, Message.COMMON_SERVER_CONNECTION_FAILURE);
			}
			JSONObject httpResp = JSON.parseObject(resp);
			boolean isSuccess = httpResp.getIntValue(RESP_STATUS) == STATUS_SUCCESS;
			if (isSuccess) {
				JSONObject respData = httpResp.getJSONObject("data");
				carPlate = respData.getString("carPlate");
			} else {
				rs = new QueryParkingFeeResultWrap();
				rs.setIsSuccess(false);
				rs.setMsg(httpResp.getString("msg"));
			}
		}
		if (!StringUtils.isEmpty(carPlate)) {
			return queryParkingFee(lot, carPlate);
		}
		return rs;
	}

	@Override
	public boolean notifyParkingFeeOrderSuccess(NotifyParkingLotMsg notify) {
		String orderSn = notify.getLocalOrderSn();
		String lotSn = notify.getLocalLotSn();
		String carPlate = notify.getCarPlate();
		log.debug("通知车场: orderSn = {}", orderSn);
		Order order = orderService.findBySn(orderSn);
		if (order != null) {
			// if (order.getPayStatus() == PayStatus.success) {
			TingzhihuiOrderSuccessNotifyRequestData data = new TingzhihuiOrderSuccessNotifyRequestData();
			data.setCarPlate(order.getCarPlate());
			ParkingIn in = inService.findByUniqueId(order.getUniqueId());
			data.setTime(in.getLastChargeTime());
			String resp = httpPost(order.getParkingLotSn(), "/api/notice", data);
			if (resp == null) {
				throw new MyException(RespMessage.Status.ERROR, Message.COMMON_SERVER_CONNECTION_FAILURE);
			}
			JSONObject httpResp = JSON.parseObject(resp);
			boolean isSuccess = httpResp.getBooleanValue(RESP_STATUS);
			if (isSuccess) {
				orderService.notifySuccess(order);
			}
			return isSuccess;
			// }
			// throw new RuntimeException("订单未支付");
		}
		throw new RuntimeException(SpringUtils.getMessage(Message.ORDER_NOT_EXISTS));
	}

	@Override
	public boolean notifyMonthCardChargeOrderSuccess(String order, String lotSn, String carPlate) {
		return false;
	}

	@Override
	public McardQueryResultWrap monthCardQuery(String lotSn, MemberCarPlate carPlate) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public McardQueryResultWrap monthCardChargePreview(String lotSn, String carPlate, Integer month) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ParkingLotInfoQueryResultWrap parkingLotInfoQuery(String lotSn) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public McardQueryChargeOptionsResultWrap monthCardQueryChargeOptions(String lotSn) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public McardChargeOrderCreateResultWrap monthCardCreateOrder(MemberCarPlate memberCarPlate, CreateMcardChargeOrderDTO dto, Platform platform) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public McardCancelResultWrap monthCardCancel(String lotSn, String carPlate) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String execute(String api, String lotSn, Map map) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void afterInNoticeHanler(HttpServletRequest request, HttpServletResponse response, ParkingLot parkingLot) {

	}

	@Override
	public void afterOutNoticeHanler(HttpServletRequest request, HttpServletResponse response, ParkingLot parkingLot) {

	}
	
	@Override
	public void beforeOutNoticeHandler(HttpServletRequest request, HttpServletResponse response, ParkingLot parkingLot) {
		// TODO Auto-generated method stub
		
	}

	/**
	 * 6秒超时
	 * 
	 * @param lotSn
	 * @param uri
	 * @param data
	 * @return
	 */
	private String httpPost(String lotSn, String uri, TingzhihuiBaseData data) {

		ParkingLot lot = lotService.findBySn(lotSn);

		Map<String, Object> body = new LinkedHashMap<>();

		body.put("appid", lotSn);
		body.put("timestamp", String.valueOf(System.currentTimeMillis()));
		body.put("nonce", RandomStringUtils.randomAlphanumeric(8));
		if (data != null) {
			body.put("data", data);
		}
		body.put("sign", SignatureUtils.signMd5(body, "key", lot.getApiKey()));
		String resp = postJson(lotSn, lot.getApiUrl() + uri, JSON.toJSONString(body), lot.getIsTcp());

		return resp;
	}
}
